# !/usr/bin/env python
# -*- coding: utf-8 -*-

"""
__project__ =  'tricker'
__file__    =  'client.py'
__author__  =  'king'
__time__    =  '2024/5/21 上午9:22'


                              _ooOoo_
                             o8888888o
                             88" . "88
                             (| -_- |)
                             O\  =  /O
                          ____/`---'\____
                        .'  \\|     |//  `.
                       /  \\|||  :  |||//  \
                      /  _||||| -:- |||||-  \
                      |   | \\\  -  /// |   |
                      | \_|  ''\---/''  |   |
                      \  .-\__  `-`  ___/-. /
                    ___`. .'  /--.--\  `. . __
                 ."" '<  `.___\_<|>_/___.'  >'"".
                | | :  `- \`.;`\ _ /`;.`/ - ` : | |
                \  \ `-.   \_ __\ /__ _/   .-` /  /
           ======`-.____`-.___\_____/___.-`____.-'======
                              `=---='
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                       佛祖保佑        永无BUG
"""

import os
import logging
import requests
from typing import Optional
from rich.logging import RichHandler

from tricker.commands.tacker.models.tacker import (
    OperationalState,
    TerminationType,
)

FORMAT = "%(message)s"
logging.basicConfig(
    level="INFO", format=FORMAT, datefmt="[%X]", handlers=[RichHandler()]
)
LOG = logging.getLogger("rich")

PROJECT_NAME = os.getenv('OS_PROJECT_NAME', 'admin')
REGION_NAME = os.getenv('OS_REGION_NAME', 'RegionOne')
USER_DOMAIN_NAME = os.getenv('OS_USER_DOMAIN_NAME', 'Default')
PROJECT_DOMAIN_NAME = os.getenv('OS_PROJECT_DOMAIN_NAME', 'Default')
USERNAME = os.getenv('OS_USERNAME', 'admin')
PASSWORD = os.getenv('OS_PASSWORD', '6qBnfwjTCtpGCvgvBl0V9K1S9FuG8nozk2kU7zF9')
AUTH_URL = os.getenv('OS_AUTH_URL', 'http://10.10.15.50:5000/v3')


class OpenStackClient(object):
    def __init__(self):
        self.session = requests.Session()
        self.headers = {'Content-Type': 'application/json'}
        self.endpoints = dict()
        self.token = self.auth()
        if self.token:
            self.headers['X-Auth-Token'] = self.token

    def vnf_instance_url(self) -> str:
        return f"{self.endpoints['tacker']}/vnflcm/v2/vnf_instances"

    def auth(self) -> str:
        data = {
            "auth": {
                "identity": {
                    "methods": ["password"],
                    "password": {
                        "user": {
                            "name": USERNAME,
                            "password": PASSWORD,
                            "domain": {"name": USER_DOMAIN_NAME},
                        },
                    },
                },
                "scope": {
                    "project": {
                        "domain": {"name": PROJECT_DOMAIN_NAME},
                        "name": PROJECT_NAME,
                    }
                },
            }
        }
        url = AUTH_URL + '/auth/tokens'
        response = self.session.post(url, json=data, headers=self.headers)
        if response.status_code >= 400:
            print(response.content)
            return ''
        else:
            endpoints = response.json()['token']['catalog']
            for endpoint in endpoints:
                url = endpoint['endpoints'][0]['url']
                self.endpoints[endpoint['name']] = url

        return response.headers.get('X-Subject-Token', '')

    def _request(
        self, url: str, action: str = 'GET', params=None, json=None
    ) -> Optional[dict]:
        response = self.session.request(
            action, url, headers=self.headers, params=params, json=json
        )
        if response.status_code >= 400:
            LOG.error(response.content)
            return None
        if response.status_code in (202, 204):
            return None
        return response.json()

    def get_vim(self, vim_name: str = 'openstack-admin-vim') -> Optional[dict]:
        url = f"{self.endpoints['tacker']}/v1.0/vims"
        vims = self._request(url).get('vims')
        for _vim in vims:
            if _vim.get('name', None) == vim_name:
                return _vim
        return None

    def create_vim(
        self, vim_name: str = 'openstack-admin-vim'
    ) -> Optional[dict]:
        url = f"{self.endpoints['tacker']}/v1.0/vims"
        data = {
            "vim": {
                "type": "openstack",
                "auth_url": AUTH_URL,
                "auth_cred": {
                    "username": USERNAME,
                    "user_domain_name": USER_DOMAIN_NAME,
                    "password": PASSWORD,
                    "cert_verify": "True",
                },
                "vim_project": {
                    "name": PROJECT_NAME,
                    "project_domain_name": PROJECT_DOMAIN_NAME,
                },
                "name": vim_name,
                "is_default": True,
            }
        }
        return self._request(url, 'post', json=data).get('vim')

    def create_package(self) -> Optional[dict]:
        url = f"{self.endpoints['tacker']}/vnfpkgm/v1/vnf_packages"
        return self._request(url, 'post', json={})

    def get_packages(self, **kwargs) -> Optional[list]:
        url = f"{self.endpoints['tacker']}/vnfpkgm/v1/vnf_packages"
        data = self._request(url, 'get', params=kwargs)
        return data
        # return data.get('vnf_packages', [])

    def get_package(self, package_id: str) -> Optional[dict]:
        url = (
            f"{self.endpoints['tacker']}/vnfpkgm/v1/vnf_packages/{package_id}"
        )
        return self._request(url, 'get')

    def update_package(
        self, package_id: str, state: str = OperationalState.DISABLED
    ) -> Optional[dict]:
        LOG.info(
            f'update vnf package {package_id} operational state to {state}'
        )
        url = (
            f"{self.endpoints['tacker']}/vnfpkgm/v1/vnf_packages/{package_id}"
        )
        data = {'operationalState': state}
        return self._request(url, 'patch', json=data)

    def get_package_onboarding_state(self, package_id: str) -> Optional[dict]:
        return self.get_package(package_id)['onboardingState']

    def upload_package(
        self,
        package_id: str,
        csar_file: str,
    ):
        url = (
            f"{self.endpoints['tacker']}/vnfpkgm/v1/"
            f"vnf_packages/{package_id}/package_content"
        )
        csar_file = open(csar_file, 'rb')
        headers = dict()
        headers.update(self.headers)
        headers['Content-Type'] = 'application/zip'
        self.session.request(
            'put',
            url,
            files={'vnf_package_content': csar_file.read()},
            headers=headers,
        )

    def delete_package(self, package_id: str):
        LOG.info(f'deleting vnf package {package_id}')
        url = (
            f"{self.endpoints['tacker']}/vnfpkgm/v1/vnf_packages/{package_id}"
        )
        self._request(url, 'delete')

    def create_vnf_instance(self, vnfd_id: str) -> Optional[dict]:
        LOG.info(f'creating vnf instance for {vnfd_id}')
        url = f"{self.endpoints['tacker']}/vnflcm/v2/vnf_instances"
        self.headers['Version'] = '2.0.0'
        return self._request(url, 'post', json={"vnfdId": vnfd_id})

    def get_vnf_instance(self, vnf_instance_id: str) -> Optional[dict]:
        url = f"{self.vnf_instance_url()}/{vnf_instance_id}"
        self.headers['Version'] = '2.0.0'
        return self._request(url, 'get')

    def delete_vnf_instance(self, vnf_instance_id: str) -> Optional[dict]:
        LOG.info(f'deleting vnf instance {vnf_instance_id}')
        url = f"{self.vnf_instance_url()}/{vnf_instance_id}"
        self.headers['Version'] = '2.0.0'
        return self._request(url, 'delete')

    def get_vnf_instances(self) -> Optional[dict]:
        self.headers['Version'] = '2.0.0'
        return self._request(self.vnf_instance_url(), 'get')

    def get_vnf_instance_instantiation_state(
        self, vnf_instance_id: str
    ) -> str:
        return self.get_vnf_instance(vnf_instance_id)['instantiationState']

    def instantiate(self, vnf_instance_id: str, data: dict):
        LOG.info(f'instantiating for {vnf_instance_id}')
        url = (
            f"{self.endpoints['tacker']}/vnflcm/v2/vnf_instances/"
            f"{vnf_instance_id}/instantiate"
        )
        self.headers['Version'] = '2.0.0'
        self._request(url, 'post', json=data)

    def terminate(self, vnf_instance_id: str):
        LOG.info(f'terminating {vnf_instance_id}')
        url = f'{self.vnf_instance_url()}/{vnf_instance_id}/terminate'
        self.headers['Version'] = '2.0.0'
        self._request(
            url, 'post', json={'terminationType': TerminationType.GRACEFUL}
        )
